/****************************************************************************
 * arch/misoc/src/lm32/lm32_allocateheap.c
 * LM32 C startup code.
 *
 * Adapted for NuttX:
 *
 *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
 *   Author: Ramtin Amin <keytwo@gmail.com>
 *
 * Derives from LatticeMico32 C startup code.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <arch/irq.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/
/* Linker memory organization ***********************************************/
/* Data memory is organized as follows:
 *
 * 1) Initialized data (.data):
 *    Start:   _sdata
 *    End(+1): _edata
 * 2) Uninitialized data (.bss):
 *    Start:   _sbss
 *    End(+1): _ebss
 *
 * The following are placed outside of the "normal" memory segments -- mostly
 * so that they do not have to be cleared on power up.
 *
 * 3) Idle thread stack:
 *    Start:   _ebss
 *    End(+1): _ebss+CONFIG_IDLETHREAD_STACKSIZE
 * 4) Heap:
 *    Start:   _ebss+CONFIG_IDLETHREAD_STACKSIZE
 *    End(+1): to the end of memory
 */

#define LM32_STACK_BASE    _ebss
#define LM32_STACK_TOP     _ebss+CONFIG_IDLETHREAD_STACKSIZE
#define LM32_HEAP_BASE     LM32_STACK_TOP

/****************************************************************************
 * Exception handlers - Must be 32 bytes long.
 ****************************************************************************/

	.section	.text, "ax", @progbits
	.global		g_idle_topstack
	.global		__start

__start:
_reset_handler:
	xor		r0, r0, r0
	wcsr	IE, r0
	mvhi	r1, hi(_reset_handler)
	ori		r1, r1, lo(_reset_handler)
	wcsr	EBA, r1
	bi		_do_reset
	nop
	nop

_breakpoint_handler:
	bi		_breakpoint_handler
	nop
	nop
	nop
	nop
	nop
	nop
	nop

_instruction_bus_error_handler:
	bi		_instruction_bus_error_handler
	nop
	nop
	nop
	nop
	nop
	nop
	nop

_watchpoint_hander:
	bi		_watchpoint_hander
	nop
	nop
	nop
	nop
	nop
	nop
	nop

_data_bus_error_handler:
	bi		_data_bus_error_handler
	nop
	nop
	nop
	nop
	nop
	nop
	nop

_divide_by_zero_handler:
	bi		_divide_by_zero_handler
	nop
	nop
	nop
	nop
	nop
	nop
	nop

_interrupt_handler:
	sw		(sp+0), ra
	calli	.save_all
	rcsr	r1, IP
	calli	lm32_decodeirq
	bi		.restore_all_and_eret
	nop
	nop
	nop

_syscall_handler:
	sw		(sp+0), ra
	addi	ea, ea, 4
	calli	.save_all
	mvi		r1, LM32_IRQ_SWINT
	calli	lm32_doirq
	bi		.restore_all_and_eret
	nop
	nop

_do_reset:
	/* Setup stack and global pointer */

	mvhi	sp, hi(LM32_STACK_TOP)
	ori		sp, sp, lo(LM32_STACK_TOP)

	/* Clear BSS */

	mvhi	r1, hi(_sbss)
	ori		r1, r1, lo(_sbss)
	mvhi	r3, hi(_ebss)
	ori		r3, r3, lo(_ebss)

.clearBSS:
	be		r1, r3, .callMain
	sw		(r1+0), r0
	addi	r1, r1, 4
	bi		.clearBSS

.callMain:
	bi		nx_start

.save_all:
	addi	sp, sp, -136
	sw		(sp+REG_X0), r0
	sw		(sp+REG_X1), r1
	sw		(sp+REG_X2), r2
	sw		(sp+REG_X3), r3
	sw		(sp+REG_X4), r4
	sw		(sp+REG_X5), r5
	sw		(sp+REG_X6), r6
	sw		(sp+REG_X7), r7
	sw		(sp+REG_X8), r8
	sw		(sp+REG_X9), r9
	sw		(sp+REG_X10), r10
	sw		(sp+REG_X11), r11
	sw		(sp+REG_X12), r12
	sw		(sp+REG_X13), r13
	sw		(sp+REG_X14), r14
	sw		(sp+REG_X15), r15
	sw		(sp+REG_X16), r16
	sw		(sp+REG_X17), r17
	sw		(sp+REG_X18), r18
	sw		(sp+REG_X19), r19
	sw		(sp+REG_X20), r20
	sw		(sp+REG_X21), r21
	sw		(sp+REG_X22), r22
	sw		(sp+REG_X23), r23
	sw		(sp+REG_X24), r24
	sw		(sp+REG_X25), r25
	sw		(sp+REG_GP), r26
	sw		(sp+REG_FP), r27

	/* Save SP before we add 136 */

	addi	r1, sp, 136
	sw		(sp+REG_SP), r1

	/* Reg RA done later */

	sw		(sp+REG_EA), r30
	sw		(sp+REG_BA), r31

	/* ra needs to be moved from initial stack location */

	lw		r1, (sp+ 136)
	sw		(sp+REG_RA), r1

	/* Get IE/REG_INT_CTX */

	rcsr	r1, IE
	sw		(sp+REG_INT_CTX), r1

	/* The 2nd argument is the regs pointer */

	addi	r2, sp, 0

	/* Move sp away from X0 */

	addi	sp, sp, -4
	ret

.restore_all_and_eret:
	/* r1 should have the place where we restore ! */

	lw		r3, (r1+REG_X3)
	lw		r4, (r1+REG_X4)
	lw		r5, (r1+REG_X5)
	lw		r6, (r1+REG_X6)
	lw		r7, (r1+REG_X7)
	lw		r8, (r1+REG_X8)
	lw		r9, (r1+REG_X9)
	lw		r10, (r1+REG_X10)
	lw		r11, (r1+REG_X11)
	lw		r12, (r1+REG_X12)
	lw		r13, (r1+REG_X13)
	lw		r14, (r1+REG_X14)
	lw		r15, (r1+REG_X15)
	lw		r16, (r1+REG_X16)
	lw		r17, (r1+REG_X17)
	lw		r18, (r1+REG_X18)
	lw		r19, (r1+REG_X19)
	lw		r20, (r1+REG_X20)
	lw		r21, (r1+REG_X21)
	lw		r22, (r1+REG_X22)
	lw		r23, (r1+REG_X23)
	lw		r24, (r1+REG_X24)
	lw		r25, (r1+REG_X25)
	lw		r26, (r1+REG_GP)
	lw		r27, (r1+REG_FP)
	lw		r28, (r1+REG_SP)
	lw		r29, (r1+REG_RA)
	lw		r30, (r1+REG_EA)
	lw		r31, (r1+REG_BA)
	lw		r2, (r1+REG_INT_CTX)
	wcsr	IE, r2
	lw		r2, (r1+REG_X2)
	lw		r1, (r1+REG_X1)

	eret

	/* This global variable is unsigned long g_idle_topstack and is
	 * exported from here only because of its coupling to other
	 * uses of _ebss in this file
	 */

	.data
	.align	4
	.type	g_idle_topstack, object

g_idle_topstack:
	.long	LM32_STACK_TOP
	.size	g_idle_topstack, .-g_idle_topstack
	.end
